// TODO: CODE REVIEW & CLEANUP!
//
// TouchField.cs
//
// A label plus content area.  Includes touch-friendly UI for selecting the control.
//

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using HomeUX.ClientControlSupport;
using HomeUX.Synchronization;

namespace HomeUX.Controls
{

[TemplatePart(Name = LayoutRootName, Type = typeof(Panel))]
[TemplatePart(Name = InnerLabelName, Type = typeof(TextBlock))]
[TemplateVisualState(GroupName = CommonStatesName, Name = NormalName)]
[TemplateVisualState(GroupName = CommonStatesName, Name = DisabledName)]
[TemplateVisualState(GroupName = FocusStatesName, Name = UnfocusedName)]
[TemplateVisualState(GroupName = FocusStatesName, Name = FocusedName)]
[TemplateVisualState(GroupName = LitStatesName, Name = UnlitStateName)]
[TemplateVisualState(GroupName = LitStatesName, Name = LitStateName)]
[TemplateVisualState(GroupName = WaitingStatesName, Name = IdleStateName)]
[TemplateVisualState(GroupName = WaitingStatesName, Name = WaitingStateName)]
public class TouchField : ContentControl, IControlHelperConnector
{
    const string LayoutRootName = "LayoutRoot";
    const string InnerLabelName = "Label";
    const string CommonStatesName = "CommonStates";
    const string NormalName = "Normal";
    const string DisabledName = "Disabled";
    const string FocusStatesName = "FocusStates";
    const string UnfocusedName = "Unfocused";
    const string FocusedName = "Focused";
    const string LitStatesName = "LitStates";
    const string UnlitStateName = "Unlit";
    const string LitStateName = "Lit";
    const string WaitingStatesName = "WaitingStates";
    const string IdleStateName = "Idle";
    const string WaitingStateName = "Waiting";

    Panel _layoutRoot;

    bool _isMouseOver;
    bool _isFocused;

    public static readonly DependencyProperty LabelProperty =
        DependencyProperty.Register("Label", typeof(object), typeof(TouchField),
        new PropertyMetadata(OnLabelPropertyChanged));

    public static readonly DependencyProperty DisplayAsFocusedProperty =
        DependencyProperty.Register("DisplayAsFocused", typeof(bool), typeof(TouchField),
        new PropertyMetadata(OnDisplayAsFocusedPropertyChanged));

    public static readonly DependencyProperty IsLitProperty =
        DependencyProperty.Register("IsLit", typeof(bool), typeof(TouchField),
            new PropertyMetadata(TouchField.OnIsLitPropertyChanged));
    public static readonly DependencyProperty IsWaitingProperty =
        DependencyProperty.Register("IsWaiting", typeof(bool), typeof(TouchField),
            new PropertyMetadata(TouchField.OnIsWaitingPropertyChanged));

    public static readonly DependencyProperty LitBackgroundProperty =
        DependencyProperty.Register("LitBackground", typeof(Brush), typeof(TouchField), null);

    public event IsWaitingChangedEventHandler IsWaitingChanged;

    public bool IsPassword { get; set; }

    public object Label
    {
        get
        {
            return GetValue(LabelProperty);
        }
        set
        {
            SetValue(LabelProperty, value);
        }
    }

    public bool DisplayAsFocused
    {
        get
        {
            return (bool)GetValue(DisplayAsFocusedProperty);
        }
        set
        {
            SetValue(DisplayAsFocusedProperty, value);
        }
    }

    public bool IsLit
    {
        get
        {
            return (bool)GetValue(IsLitProperty);
        }
        set
        {
            SetValue(IsLitProperty, value);
        }
    }

    public bool IsWaiting
    {
        get
        {
            return (bool)GetValue(IsWaitingProperty);
        }
        set
        {
            SetValue(IsWaitingProperty, value);
        }
    }

    public Brush LitBackground
    {
        get
        {
            return (Brush)GetValue(LitBackgroundProperty);
        }
        set
        {
            SetValue(LitBackgroundProperty, value);
        }
    }

    public TouchField()
    {
        DefaultStyleKey = typeof(TouchField);
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        ControlHelper.GetRequiredTemplateChild(this, LayoutRootName, out _layoutRoot);
        _layoutRoot.MouseEnter += new System.Windows.Input.MouseEventHandler(_layoutRoot_MouseEnter);
        _layoutRoot.MouseLeave += new System.Windows.Input.MouseEventHandler(_layoutRoot_MouseLeave);

        IsEnabledChanged += new DependencyPropertyChangedEventHandler(TouchField_IsEnabledChanged);

        UpdateLabel();
    }

    void UpdateLabel()
    {
        // do nothing if OnApplyTemplate has not been called yet
        if (_layoutRoot == null)
            return;

        object label = Label;
        if (label != null)
        {
            UIElement labelElement;
            string labelString;
            if ((labelString = label as string) != null)
            {
                TextBlock innerLabel;
                ControlHelper.GetRequiredTemplateChild(this, InnerLabelName, out innerLabel);
                innerLabel.Text = labelString;
            }
            else
            if ((labelElement = label as UIElement) != null)
            {
                Panel panel;
                ControlHelper.GetRequiredTemplateChild(this, "LabelParent", out panel);
                panel.Children.Clear();
                panel.Children.Add(labelElement);
            }
            else
                throw new Exception("Label must be either a string or a UIElement");
        }
    }

    void TouchField_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        UpdateVisualState(true);
    }

    void _layoutRoot_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
    {
		_isMouseOver = true;
		UpdateVisualState(true);
    }

    void _layoutRoot_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
    {
		_isMouseOver = false;
		UpdateVisualState(true);
    }

    static void OnDisplayAsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (TouchField)d;
        target._isFocused = (bool) e.NewValue;
		target.UpdateVisualState(true);
    }

    static void OnLabelPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (TouchField)d;
        target.UpdateLabel();
    }

    static void OnIsLitPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (TouchField)d;
        target.UpdateVisualState(true);
    }

    static void OnIsWaitingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (TouchField)d;
        target.UpdateVisualState(true);

        // fire the IsWaitingChanged event
        if (target.IsWaitingChanged != null)
        {
            target.IsWaitingChanged(target, new IsWaitingChangedEventArgs()
            {
                IsWaiting = (bool)e.NewValue
            });
        }
    }

    void UpdateVisualState(bool useTransitions)
    {
        if (IsEnabled)
            VisualStateManager.GoToState(this, NormalName, useTransitions);
        else
            VisualStateManager.GoToState(this, DisabledName, useTransitions);

        if ((_isFocused || _isMouseOver) && !ClientGlobals.IsTouchMode)
            VisualStateManager.GoToState(this, FocusedName, useTransitions);
        else
            VisualStateManager.GoToState(this, UnfocusedName, useTransitions);

        if (IsLit)
            VisualStateManager.GoToState(this, LitStateName, useTransitions);
        else
            VisualStateManager.GoToState(this, UnlitStateName, useTransitions);

        if (IsWaiting)
            VisualStateManager.GoToState(this, WaitingStateName, useTransitions);
        else
            VisualStateManager.GoToState(this, IdleStateName, useTransitions);
    }

    Control IControlHelperConnector.GetControl()
    {
        return this;
    }

    DependencyObject IControlHelperConnector.GetTemplateChild(string childName)
    {
        return GetTemplateChild(childName);
    }
}

}
